package com.feitubc.tools.fileimport.strategy;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.alibaba.fastjson.JSON;
import com.feitubc.tools.fileimport.BaseLogService;
import com.feitubc.tools.fileimport.IStrategyImportFile;
import com.feitubc.tools.fileimport.StrategyContext;
import com.feitubc.tools.fileimport.domain.ImportFileResultEnum;
import com.feitubc.tools.fileimport.domain.ImportLogObject;
import com.feitubc.tools.fileimport.util.PropertiesHelper;
import com.feitubc.tools.fileimport.util.ReadExcelByExtHelper;
import com.feitubc.tools.fileimport.util.SpringContextHelper;

/**
 * 批量修改导入公共模板
 * 
 * @author zhc
 */
public abstract class AbstractImportFileTemplate<T extends ImportLogObject> implements IStrategyImportFile {
	
	protected final Log logger = LogFactory.getLog(this.getClass());
	
	/**
	 * 执行导入文件服务
	 * // 1.校验参数是否正常 
	 * // 2.解析文件数据
	 * // 3.根据file数据转换为具体对象
	 * // 4.执行数据前，整体校验数据有效性，建议不使用多线程
	 * // 5.执行数据
	 * // 6.处理完成后，保存日志记录
	 */
	public boolean execute(StrategyContext strategyContext) {
		
		boolean result = false;
		try {
			
			// 1.校验参数是否正常 
			// 2.解析文件数据
			// 3.根据file数据转换为具体对象
			// 4.执行数据前，整体校验数据有效性，建议不使用多线程
			if (this.preCheckParam(strategyContext) 
						&& this.parseFileDataFromInputStream(strategyContext) 
						&& this.preDataFromFileDataMap(strategyContext)
						&& this.preExecuteData(strategyContext)) {
				if (strategyContext.getExecuteDataList() != null && strategyContext.getExecuteDataList().size() > 0) {
					// 5.执行数据
					this.executeImport(strategyContext);
					result = strategyContext.getSuccessCount() == strategyContext.getExecuteDataList().size();
				} else {
					strategyContext.setCodeByResultEnum(ImportFileResultEnum.DATA_EMPTY_ERROR);
				}
			}
			if (result) {
				strategyContext.setCodeByResultEnum(ImportFileResultEnum.SUCCESS);
			} else {
				strategyContext.setCodeByResultEnum(ImportFileResultEnum.BUSINESS_PARAM_ERROR);
			}
		} catch (Exception e) {
			strategyContext.setCodeByResultEnum(ImportFileResultEnum.BUSINESS_ERROR, "处理异常：" + e.getMessage());
			this.logger.error(String.format("AbstractImportFileTemplate#execute ERROR param【%s】 :", 
					JSON.toJSONString(strategyContext)), e);
		}
		// 6.处理完成后，保存日志记录
		try {
			afterImport(strategyContext);
		} catch (Exception e) {
			this.logger.error(String.format("AbstractImportFileTemplate#afterImport param【%s】 ERROR:", 
					JSON.toJSONString(strategyContext)), e);
		}
		return result;
	}

	/**
	 * 1.校验参数是否正常 
	 * @param strategyContext
	 * @return
	 */
	protected boolean preCheckParam(StrategyContext strategyContext) {
		if (strategyContext == null || strategyContext.getInputStream() == null 
				|| strategyContext.getFileStrategySetting() == null
				|| StringUtils.isBlank(strategyContext.getFilename())) {
			this.logger.error(String.format("AbstractImportFileTemplate#preCheckParam param【%s】 ERROR", 
					JSON.toJSONString(strategyContext)));
			strategyContext.setCodeByResultEnum(ImportFileResultEnum.FILE_PARAM_ERROR);
			return false;
		}
		return true;
	}
	
	/**
	 * 2.解析文件数据
	 * @param strategyContext
	 * @return
	 */
	private boolean parseFileDataFromInputStream(StrategyContext strategyContext) {
		
		// 组装数据
		InputStream inputStream = strategyContext.getInputStream();
		try {
			
			TreeMap<Integer, Map<Integer, Object>> fileDataMap = ReadExcelByExtHelper.readExcelFromInputStream(inputStream, strategyContext.getFilename());
			
			if (fileDataMap != null && !fileDataMap.isEmpty()) {
				strategyContext.setFileDataMap(fileDataMap);
				strategyContext.setInputStream(null);
				return true;
			}
			
		} catch (IOException e) {
			this.logger.error("AbstractImportFileTemplate#preDataFromInputStream read readFile Exception :", e);
		} finally {
			try {
				if (inputStream != null) {
					inputStream.close();
				}
			} catch (Exception e2) {
				this.logger.error("AbstractImportFileTemplate#preDataFromInputStream close readFile Exception :", e2);
			}
		}
		return false;
	}

	
	/**
	 * 3.根据file数据转换为具体对象
	 * @param strategyContext
	 * @return
	 */
	protected abstract boolean preDataFromFileDataMap(StrategyContext strategyContext);


	/**
	 * 4.执行数据前，整体校验数据有效性，建议不使用多线程
	 * @param strategyContext
	 * @return
	 */
	protected abstract boolean preExecuteData(StrategyContext strategyContext);
	
	/**
	 * 5.执行数据
	 * @param strategyContext
	 * @return
	 */
	protected abstract boolean executeImport(StrategyContext strategyContext);
	
	/**
	 * // 6.处理完成后，保存日志记录
	 * @param strategyContext
	 */
	protected void afterImport(StrategyContext strategyContext) {
		try {
			if (strategyContext != null && strategyContext.getFileStrategySetting().isSaveLog()) {
				if (strategyContext.getImportLogObjects() != null && strategyContext.getImportLogObjects().size() > 0) {
					this.saveOperateLog(strategyContext.getImportLogObjects());
				}
			}
		} catch (Exception e) {
			this.logger.error(String.format("AbstractImportFileTemplate#afterImport saveOperateLog ERROR param【%s】 :", 
					JSON.toJSONString(strategyContext)), e);
		}
	}
	
	/**
	 * 记录日志信息
	 * @param importLogObjects
	 */
	@SuppressWarnings("unchecked")
	protected boolean saveOperateLog(List<ImportLogObject> importLogObjects) {
		try {
			String baseLogServiceName = PropertiesHelper.newInstance().getValue("baseLogService.name");
			if (StringUtils.isBlank(baseLogServiceName)) {
				throw new RuntimeException("AbstractImportFileTemplate#saveOperateLog [baseLogService.name] is not be set");
			}
			Object baseLogService = SpringContextHelper.getBean(baseLogServiceName);
			if (baseLogService == null) {
				throw new RuntimeException("AbstractImportFileTemplate#saveOperateLog baseLogService is not be implement");
			}
			return ((BaseLogService<T>)baseLogService).insert((List<T>) importLogObjects);
		} catch (Exception e) {
			this.logger.error("AbstractImportFileTemplate#saveOperateLog ERROR :", e);
			return false;
		}
	}
}
